package com.hyt.it.ogt.kq.service.gov.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.it.ogt.kq.common.exception.GovInvalidRequestException;
import com.hyt.it.ogt.kq.common.gov.constant.CodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.service.gov.mapper.OfficeRoomMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficeArea;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficePlace;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficeRoom;
import com.hyt.it.ogt.kq.service.gov.model.param.FiltrateRoomParam;
import com.hyt.it.ogt.kq.service.gov.model.param.OfficeRoomParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.FiltrateRoomPageVO;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeAreaService;
import com.hyt.it.ogt.kq.service.gov.service.IOfficePlaceService;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeRoomService;
import com.hyt.model.PageParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 考场信息表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Service
public class OfficeRoomServiceImpl extends BaseServiceImpl<OfficeRoomMapper, OfficeRoom> implements IOfficeRoomService {

    @Autowired
    private IOfficePlaceService iOfficePlaceService;

    @Resource
    private OfficeRoomMapper officeRoomMapper;

    @Resource
    private IOfficeAreaService iOfficeAreaService;

    @Resource
    private IOfficeRoomService iOfficeRoomService;

    @Override
    @Transactional(rollbackFor = NestedBusinessException.class)
    public void add(OfficeRoomParam officeRoomParam, String officeId) throws GovInvalidRequestException {
        //校验考点
        OfficePlace officePlace = this.checkPlace(officeRoomParam);
        //校验考场
        this.checkRoomByAdd(officeRoomParam);
        //生成考场编号
        OfficeRoom newOfficeRoom = this.generateRoomCode(officeRoomParam, officePlace, officeId);
        newOfficeRoom.setAnswerType(officeRoomParam.getAnswerType() == null ? CodeEnum.COMPUTER_EXAM.getCode() : officeRoomParam.getAnswerType());
        //插入机构考场信息模板
        this.insertOfficeRoom(newOfficeRoom);
    }

    @Override
    @Transactional(rollbackFor = NestedBusinessException.class)
    public void update(OfficeRoomParam officeRoomParam) throws GovInvalidRequestException {
        //校验考点
        this.checkPlace(officeRoomParam);
        //校验考场
        OfficeRoom currentOfficeRoom = this.checkRoomByUpdate(officeRoomParam);
        //更新机构考场信息模板
        this.updateOfficeRoom(currentOfficeRoom, officeRoomParam);
    }

    @Override
    public Page<FiltrateRoomPageVO> filtratePage(PageParam<FiltrateRoomPageVO> pageParam, FiltrateRoomParam filtrateRoomParam, String officeId) {

        Page<FiltrateRoomPageVO> page = officeRoomMapper.filtratePage(pageParam, filtrateRoomParam, officeId);
        List<FiltrateRoomPageVO> filtrateRoomPageVOList = page.getRecords();

        Map<String, OfficeArea> mapOfficeArea = new HashMap<>(16);
        if (!filtrateRoomPageVOList.isEmpty())  {
            mapOfficeArea = iOfficeAreaService.getOfficeAreaMap(officeId);
        }

        Map<String, OfficeArea> finalMapOfficeArea = mapOfficeArea;
        if(CollUtil.isNotEmpty(filtrateRoomPageVOList)) {
        	filtrateRoomPageVOList.stream().forEach(filtrateRoomPageVO -> {
                filtrateRoomPageVO.setProvinceName(finalMapOfficeArea.get(filtrateRoomPageVO.getProvince())==null?null:finalMapOfficeArea.get(filtrateRoomPageVO.getProvince()).getName())
                        .setCityName(finalMapOfficeArea.get(filtrateRoomPageVO.getCity())==null?null:finalMapOfficeArea.get(filtrateRoomPageVO.getCity()).getName())
                        .setDistrictName(finalMapOfficeArea.get(filtrateRoomPageVO.getDistrict())==null?null:finalMapOfficeArea.get(filtrateRoomPageVO.getDistrict()).getName());
            });
        }
        return page;
    }

    @Override
    public OfficeRoom getByCode(String code) {
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficeRoom::getCode, code)
                .eq(OfficeRoom::getDelFlag, false);
        return getOne(queryWrapper);
    }

    /**
     * 更新机构考场信息模板
     * @param currentOfficeRoom 被编辑的考场
     * @param officeRoomParam 编辑考场参数
     * @throws NestedBusinessException 更新失败，抛出异常
     */
    private void updateOfficeRoom(OfficeRoom currentOfficeRoom, OfficeRoomParam officeRoomParam) throws NestedBusinessException {
        BeanUtils.copyProperties(officeRoomParam, currentOfficeRoom);
        if (!updateById(currentOfficeRoom)) {
            throw new NestedBusinessException("更新机构考场信息模板表失败");
        }
    }

    /**
     * 插入机构考场信息模板
     * @param officeRoom 添加考场参数
     * @throws NestedBusinessException 插入失败，抛出异常
     */
    private void insertOfficeRoom(OfficeRoom officeRoom) throws NestedBusinessException {
        if (!save(officeRoom)) {
            throw new NestedBusinessException("插入机构考场信息模板表失败");
        }
    }

    /**
     * 生成考场编号
     * 生成规则：所属考点编号 + 考场自增序号
     * @param officeRoomParam 添加考场参数
     * @param officePlace 所属考点信息
     * @param officeId 机构id
     */
    @Override
    public OfficeRoom generateRoomCode(OfficeRoomParam officeRoomParam, OfficePlace officePlace, String officeId) {
        // 考场编号
        Integer  mapRoomMaxSort = iOfficeRoomService.officeRoomMaxSort(officeId);
        //创建插入机构考场信息参数对象
        OfficeRoom newOfficeRoom = new OfficeRoom();
        BeanUtils.copyProperties(officeRoomParam, newOfficeRoom);
        //设置新考场的机构id和考场状态为可用
        newOfficeRoom.setOfficeId(officeId)
                .setStatus(CodeEnum.ROOM_STATUS_USABLE.getCode());
        //在数据库中查询当前机构、当前考点下的考场的最大自增序号
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficeRoom::getPlaceId, officeRoomParam.getPlaceId())
                .eq(OfficeRoom::getDelFlag, false);
        List<OfficeRoom> officeRoomList = list(queryWrapper);
        //拼接所属考点编号
        Integer placeCode = officePlace.getCode();
        StringBuffer stringBuffer = new StringBuffer(String.valueOf(placeCode));
        //若当前机构、当前考点下不存在考场，则初始化一个新的考场编号
        if (CollectionUtils.isEmpty(officeRoomList)) {
            //拼接初始自增序号
            stringBuffer.append("1");
            newOfficeRoom.setSort(1)
                    .setCode(Integer.valueOf(stringBuffer.toString()));
            return newOfficeRoom;
        }
        newOfficeRoom.setCode(++mapRoomMaxSort);
        return newOfficeRoom;
    }

    /**
     * 校验考点
     * @param officeRoomParam 考场参数
     * @throws GovInvalidRequestException 考点已不存在，抛出异常
     */
    private OfficePlace checkPlace(OfficeRoomParam officeRoomParam) throws GovInvalidRequestException {
        String placeId = officeRoomParam.getPlaceId();
        QueryWrapper<OfficePlace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficePlace::getId, placeId)
                .eq(OfficePlace::getDelFlag, false);
        OfficePlace officePlace = iOfficePlaceService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(officePlace)) {
            //所属考点已不存在
            throw new GovInvalidRequestException(ResponseCode.ROOM_FOR_NON_EXIST.getCode(),
                    ResponseCode.ROOM_FOR_NON_EXIST.getMsg());
        }
        return officePlace;
    }

    /**
     * 校验添加考场参数
     * @param officeRoomParam 考场参数
     * @throws GovInvalidRequestException 考场参数校验不通过，抛出异常
     */
    private void checkRoomByAdd(OfficeRoomParam officeRoomParam) throws GovInvalidRequestException {
        //获取当前考点下所有考场
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficeRoom::getPlaceId, officeRoomParam.getPlaceId())
                .eq(OfficeRoom::getDelFlag, false);
        List<OfficeRoom> officeRoomList = list(queryWrapper);
        //校验考场名称是否重复
        if (!CollectionUtils.isEmpty(officeRoomList)) {
            String name = officeRoomParam.getName();
            boolean repeat = officeRoomList.stream()
                    .anyMatch(officeRoom -> officeRoom.getName().equals(name));
            if (repeat) {
                //当前考点下存在名称相同的考场
                throw new GovInvalidRequestException(ResponseCode.ROOM_EXIST_IN_PLACE.getCode(),
                        ResponseCode.ROOM_EXIST_IN_PLACE.getMsg());
            }
        }
    }

    /**
     * 校验编辑考场参数
     * @param officeRoomParam 考场参数
     * @throws GovInvalidRequestException 考场参数校验不通过，抛出异常
     */
    private OfficeRoom checkRoomByUpdate(OfficeRoomParam officeRoomParam) throws GovInvalidRequestException {
        //获取当前考点下所有考场
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficeRoom::getPlaceId, officeRoomParam.getPlaceId())
                .eq(OfficeRoom::getDelFlag, false);
        List<OfficeRoom> officeRoomList = list(queryWrapper);
        //获取被编辑的考场
        OfficeRoom currentOfficeRoom = null;
        for (OfficeRoom officeRoom : officeRoomList) {
            if (officeRoom.getId().equals(officeRoomParam.getId())) {
                currentOfficeRoom = officeRoom;
            }
        }
        if (ObjectUtils.isEmpty(currentOfficeRoom)) {
            //当前考场已不存在
            throw new GovInvalidRequestException(ResponseCode.ROOM_CURRENT_NON_EXIST.getCode(),
                    ResponseCode.ROOM_CURRENT_NON_EXIST.getMsg());
        }
        //编辑考场的情况下需要忽略被编辑的考场
        officeRoomList = officeRoomList.stream()
                .filter(officeRoom -> !officeRoom.getId().equals(officeRoomParam.getId()))
                .collect(Collectors.toList());
        //校验考场名称是否重复
        boolean repeat = officeRoomList.stream()
                .anyMatch(officeRoom -> officeRoom.getName().equals(officeRoomParam.getName()));
        if (repeat) {
            //当前考点下存在名称相同的考场
            throw new GovInvalidRequestException(ResponseCode.ROOM_NAME_EXIST_IN_PLACE.getCode(),
                    ResponseCode.ROOM_NAME_EXIST_IN_PLACE.getMsg());
        }
        return currentOfficeRoom;
    }

    @Override
    public Integer officeRoomMaxSort(String officeId) {
        OfficeRoom officeRoom = this.lambdaQuery()
               .eq(OfficeRoom::getOfficeId,officeId)
               .eq(OfficeRoom::getDelFlag,false)
               .select(OfficeRoom::getCode)
               .orderByDesc(OfficeRoom::getCode)
               .last("limit 1").one();

        if (officeRoom == null) {
            return 0;
        }

        return officeRoom.getCode();
    }

}
